package sisicotren.model.simulator;

import estadistica.PoissonEventGenerator;
import sisicotren.model.simulator.Channel;
import sisicotren.util.Log;

import java.util.Observable;

public class ClientChannelDispatcher extends Observable implements Runnable {

	public ClientChannelDispatcher(Channel ch) {
		super();
		targetChannel = ch;
		evtGen = new PoissonEventGenerator(ch.getAttentionRate());
		clientsDispatched = 0;
	}
	
	public void run() {
		Double lastEvtTime = 0.00;
		clientsDispatched = 0;
		while(targetChannel.getCurrentState() != ChannelState.OFF) {
			if(targetChannel.getCurrentState() == ChannelState.BUSY) {
				Double evtTime = evtGen.getNextEventTime();
				Double delta = evtTime - lastEvtTime;
				try {
					Log.print("ClientChannelDispatcher, Sleep :[" + (long)(delta * time.time() * 1000.00) +"]");
					Thread.sleep((long)(delta * ClientChannelDispatcher.time.time() * 1000.00));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// podria haber desactivado el canal durante el sleep
				if(targetChannel.getCurrentState() == ChannelState.BUSY) {
					targetChannel.setCurrentState(ChannelState.IDLE);
					Log.print("ClientChannelDispatcher, dispatch another client.");
					lastEvtTime = evtTime;
					clientsDispatched++;
					this.setChanged();
					this.notifyObservers(this.targetChannel.getServedClients().size());
				}
			}
			Thread.yield();
		}
		Log.print("ClientChannelDispatcher, is OFF");
	}
	
	public void stop() {
		targetChannel.setCurrentState(ChannelState.OFF);
	}
	
	public void resume() {
		if(this.previousPausedState == null)
			return;
		
		if(targetChannel.getCurrentState() == ChannelState.PAUSED) {
			targetChannel.setCurrentState(this.previousPausedState);
			this.previousPausedState = null;
		}
	}
	
	public void pause() {
		if(targetChannel.getCurrentState() != ChannelState.PAUSED) {
			this.previousPausedState = targetChannel.getCurrentState();
			targetChannel.setCurrentState(ChannelState.PAUSED);
		}
	}
	
	public static SimulationTimeOptions getTimeOptions() {
		return ClientChannelDispatcher.time;
	}
	
	public static void setTimeOptions(SimulationTimeOptions time) {
		ClientChannelDispatcher.time = time;
	}
	
	private PoissonEventGenerator evtGen;
	private Channel targetChannel;
	private ChannelState previousPausedState = null;
	private static SimulationTimeOptions time = SimulationTimeOptions.REAL_TIME;
	private Integer clientsDispatched = 0;
}
